﻿/*
 * Created by SharpDevelop.
 * User: Administrator
 * Date: 3/1/2011
 * Time: 8:30 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using TomatoSynchronizer.Entities;
using TomatoSynchronizer.Store;
using HtmlAgilityPack;

namespace TomatoSynchronizer.Synchronizer
{
	/// <summary>
	/// Description of LanguageSynchronizer
	/// </summary>
	public static class LanguageSynchronizer
	{
		public static void Synchronize(Site siteSrc,Site siteDest,HtmlWeb client,SyncDirection direction)
		{
			switch(direction)
			{
				case SyncDirection.Download:
					UpLoadItems(siteDest,siteSrc,client,direction);
					break;
				case SyncDirection.Upload:
					UpLoadItems(siteSrc,siteDest,client,direction);
					break;
				case SyncDirection.DownloadAndUpload:
					UpLoadItems(siteDest,siteSrc,client,SyncDirection.Download);
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);
					break;
				case SyncDirection.UploadAndDownload:
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);
					UpLoadItems(siteDest,siteSrc,client,SyncDirection.Download);
					break;
				case SyncDirection.Synchronize:
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);
					
					LanguageStore LanguageStoreSrc = new LanguageStore(siteSrc,client);
					LanguageStore LanguageStoreDest = new LanguageStore(siteDest,client);
					
					Language[] LanguagesDest =  LanguageStoreDest.LoadItems();
					
					foreach(Language languageDest in LanguagesDest)
					{
						Language languageSrc = LanguageStoreSrc.LoadItem(languageDest.languages_id);
						
						if(languageSrc == null)
						{
							LanguageStoreDest.DeleteItem(languageDest.languages_id);
						}
						else
						{
							foreach(TranslationGroup group in languageDest.TranslationGroups)
							{
								foreach(Translation translation in group.Translations)
								{
									translation.languages_id = languageDest.languages_id;
									
									var trans = languageSrc.LoadTranslation(group.id,translation.definition_key);
									
									if(trans == null)
									{
										foreach(TranslationGroup groupSrc in languageSrc.TranslationGroups)
										{
											foreach(Translation translationSrc in groupSrc.Translations)
											{																																																
												if(translationSrc.definition_key == translation.definition_key)
												{
													LanguageStoreSrc.DeleteTranslation(translationSrc);
												}
											}
										}										
									}
								}
							}
						}
					}
					break;
			}
		}
		
		private static void UpLoadItems(Site _siteSrc,Site _siteDest,HtmlWeb client,SyncDirection direction)
		{
			LanguageStore LanguageStoreSrc = new LanguageStore(_siteSrc,client);
			LanguageStore LanguageStoreDest = new LanguageStore(_siteDest,client);
			
			Language[] LanguagesSrc =  LanguageStoreSrc.LoadItems();
			Language[] LanguagesDest =  LanguageStoreDest.LoadItems();
			
			MappingStore mappingStoreSrc = new MappingStore(_siteSrc,_siteDest,"languages_id");
			MappingStore mappingStoreDest = new MappingStore(_siteDest,_siteSrc,"languages_id");
			
			mappingStoreSrc.Clean<Language>(LanguageStoreSrc,LanguageStoreDest);
			mappingStoreDest.Clean<Language>(LanguageStoreDest,LanguageStoreSrc);
			
			foreach(Language LanguageSrc in LanguagesSrc)
			{
				//we assume the Language is not yet synchronized
				bool synchronized = false;
				
				//we check if a mapping already exists for this Language in the destination store
				foreach(Mapping mapping in mappingStoreSrc.Mappings)
				{
					if(!synchronized)
					{
						if(mapping.SrcValue == LanguageSrc.languages_id)
						{
							if(!string.IsNullOrEmpty(mapping.DestValue))
							{
								//this Language already exists in the destination store
								//we check if everything changed since the last synchronization
								Language LanguageDest = LanguageStoreDest.GetItem(mapping.DestValue);
								if(!string.IsNullOrEmpty(LanguageDest.languages_id))
								{
									synchronized = SynchronizeItem(LanguageSrc,LanguageDest,direction,mappingStoreSrc);
								}
								else
								{
									//the mapping exists, but the Language has been deleted in the destination store
									//we set a flag that this mapping does not exists anymore
									mapping.Exists = false;
								}
							}
						}
					}
				}
				
				if(!synchronized)
				{
					//there is no mapping, we check if this Language already exists in the destination store
					foreach(Language LanguageDest in LanguagesDest)
					{
						if(LanguageSrc.code == LanguageDest.code)
						{
							//we get the 2 currencies from sites to get sure they really exist
							Language src = LanguageSrc.Store.GetItem(LanguageSrc.languages_id);
							Language dest = LanguageDest.Store.GetItem(LanguageDest.languages_id);
							
							if(src != null)
							{
								if(dest != null)
								{
									Mapping mapping = new Mapping(LanguageSrc.languages_id,LanguageDest.languages_id,"languages_id");
									mappingStoreSrc.Mappings.Add(mapping);
									
									synchronized = SynchronizeItem(LanguageSrc,LanguageDest,direction,mappingStoreSrc);
								}
								else
								{
									synchronized = false;
								}
							}
							else
							{
								synchronized = true;
							}
						}
					}
				}
				
				if(!synchronized)
				{
					//no mapping the Language is new
					//we insert it in the destination store
					string remoteId = string.Empty;
					
					remoteId = LanguageStoreDest.InsertItem(LanguageSrc);
					
					synchronized = remoteId != string.Empty;
					
//						synchronized = true;
					
					if(!synchronized)
					{
						throw new Exception("The Language " + LanguageSrc.name + " has not been synchronized");
					}
					
					Mapping mapping = new Mapping(LanguageSrc.languages_id,remoteId,"languages_id");
					mappingStoreSrc.Mappings.Add(mapping);
					synchronized = true;
				}
				
				if(!synchronized)
				{
					throw new Exception("could not synchronize the Language " + LanguageSrc.name);
				}
				
				LanguageStoreSrc.PersistItem(LanguageSrc);
			}
			
			mappingStoreSrc.Save();
			
			mappingStoreDest.Truncate();
			
			//we save the mappings in the destination MappingStore too
			foreach(Mapping mapping in mappingStoreSrc.Mappings)
			{
				if(mapping.Exists)
				{
					Mapping mappingDest = new Mapping(mapping.DestValue,mapping.SrcValue,mapping.Property);
					mappingStoreDest.Mappings.Add(mappingDest);
				}
			}
			
			mappingStoreDest.Save();						
			
			//we check if the 2 MappingStore are synchronized
			if(mappingStoreSrc.Mappings.Count != mappingStoreDest.Mappings.Count)
			{
				throw new Exception("The mapping store are not synchronized");
			}
		}
		
		private static bool SynchronizeItem(Language LanguageSrc,Language LanguageDest,SyncDirection direction,MappingStore mappingStore)
		{
			bool synchronized = true;
			
			if(!LanguageSrc.Equals(LanguageDest))
			{
				synchronized = false;
				
				//we update the destination Language
				LanguageSrc.languages_id = LanguageDest.languages_id;
				LanguageSrc.currencies_id = LanguageDest.currencies_id;
				LanguageSrc.parent_id = LanguageDest.parent_id;
				
				synchronized = LanguageDest.Store.UpdateItem(LanguageSrc);
			}
			
			return synchronized;
		}
		
		private static string UploadItem(LanguageStore LanguageStoreDest,Language Language)
		{
			string remoteId = string.Empty;
			
			remoteId = LanguageStoreDest.InsertItem(Language);
			
			return remoteId;
		}
	}
}
